// TcpServer类定义  单例模式  懒汉模式 
// 基本网路接口封装  套接字  绑定  监听  


/*
- 文件名尽量全部小写, 可以包含下划线 (_) 
- 变量名使用小写字母，单词之间使用下划线分隔。
- 函数名使用驼峰命名法，即首字母小写，后面的单词首字母大写，不使用下划线。
- 类名使用驼峰命名法，即每个单词首字母大写，不使用下划线。
- 常量名使用全大写字母，单词之间使用下划线分隔。
*/
#pragma once
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>

#include "log.hpp"

#define BACKLOG 5   // 宏观理解为允许 listen -> accept 的用户数  ？？？

class TcpServer
{
    //成员变量
    private:
    int _port ;                 //端口号
    int _listen_sock ;          //
    static TcpServer* _ser ;    //静态成员变量必须在类外初始化 ——> 调用类内函数实现单例模式

    //单例模式私有构造函数
    private:

    TcpServer(int port = 8080)
    :_port(port)
    ,_listen_sock(-1)
    {

    }

    //防拷贝->实现单例
    TcpServer(const TcpServer* ser)
    {
        
    }

    public:

    // 单例获取函数
    static TcpServer* getinstance(int port = 8080)
    {
        // 静态初始化互斥量
        static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER ;
        if(nullptr == _ser)
        {
            pthread_mutex_lock(&lock) ;
            
            if(nullptr == _ser)
            {
                _ser = new TcpServer(port) ;
                _ser->initServer(); 
            }   

            pthread_mutex_unlock(&lock) ;
        }

        return _ser ; 
    }

    //socket 
    void socketPacked()
    {
        _listen_sock = socket(AF_INET, SOCK_STREAM, 0) ; 
        if(0 > _listen_sock)
        {
            // 创建套接字失败
            LOG(FATAL, "create sock error");
            exit(-1);
        }
        //存放setsockopt选项设置值  
        int opt = 1 ; 
        //- SOL_SOCKET：通用套接字选项           
        //- SO_REUSEADDR：允许重用本地地址和端口  

        /*SO_REUSEADDR选项允许多个套接字绑定到相同的地址和端口组合。
        这在需要快速关闭并重新打开套接字的情况下很有用，
        而不需要等待操作系统释放与先前套接字相关的资源*/
        
        setsockopt(_listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        LOG(INFO, "crate sock sucess") ;

    }

    //
    void bindPacked()
    {
        sockaddr_in local ; 
        memset(&local, 0, sizeof(local));
        local.sin_port = _port ; 
        local.sin_family = AF_INET ;
        //INADDR_ANY表示希望绑定到本地的任意IP地址
        //云服务器不能直接绑定公网IP! ! !
        local.sin_addr.s_addr = INADDR_ANY ; 
        LOG(INFO, "bind sock success") ;

        /* 
        
        if(bind(_listen_sock, (struct sockaddr *) &local, sizeof(local)) == -1)
        {
            LOG(WARNING, "bind sock error") ; 
        } 
        
        */

    }

    void listenPacked()
    {
        if(0 > listen(_listen_sock, BACKLOG))
        {
            //监听套接字失败
            LOG(FATAL, "listen sock failed") ;
            exit(3);
        } 
        LOG(INFO, "linten sock sucess");
    }

    
    void initServer()
    {
        socketPacked();
        bindPacked();
        listenPacked();
        LOG(INFO, "init server sucess") ;
    }

    ~TcpServer()
    {
        if(0 < _listen_sock)
        {
            close(_listen_sock) ;
        }
    }

    int get_sock()
    {
        return _listen_sock ; 
    }

};


//类外初始化静态成员

 TcpServer* TcpServer::_ser = nullptr ; 







